package cn.kzgg.ymcc.service.impl;

import cn.kzgg.ymcc.feign.login.LoginFeignClient;
import cn.kzgg.ymcc.constants.CommonConstants;
import cn.kzgg.ymcc.domain.*;
import cn.kzgg.ymcc.dto.RedisRegisterDto;
import cn.kzgg.ymcc.dto.RegisterDto;
import cn.kzgg.ymcc.mapper.UserMapper;
import cn.kzgg.ymcc.result.JSONResult;
import cn.kzgg.ymcc.service.IRemoveBlackService;
import cn.kzgg.ymcc.service.IUserAccountService;
import cn.kzgg.ymcc.service.IUserBaseInfoService;
import cn.kzgg.ymcc.service.IUserService;
import cn.kzgg.ymcc.util.AssertUtil;
import cn.kzgg.ymcc.util.BitStatesUtils;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;

/**
 * <p>
 * 会员登录账号 服务实现类
 * </p>
 *
 * @author kzgg
 * @since 2022-07-15
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private LoginFeignClient loginFeignClient;

    @Autowired
    private IUserBaseInfoService userBaseInfoService;

    @Autowired
    private IUserAccountService userAccountService;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private IRemoveBlackService removeBlackService;

    /**
     * 注册
     *
     * 1.参数校验
     * 2.验证码是否正确
     * 3.手机号不能被注册
     * ==保存
     *  保存t_login
     *    。在service-uaa编写controller接口，调用service保存t_login数据
     *    。为service-uaa的controller编写Feign，给service-user调用
     *  保存user相关
     *    调用对应的service保存数据即可 t_user  t_user_base_info  t_user_account
     * @param registerDto
     */
    @Override
    //@Transactional
    @GlobalTransactional
    public void register(RegisterDto registerDto) {
//        1.参数校验
//        2.验证码是否正确
        //2.1.首先获取验证码拼接的key值
        String key = String.format(CommonConstants.REGISTER_MOBILE_PROFIX, registerDto.getMobile());
        //2.2根据key值获取redi中存储的值
        Object o = redisTemplate.opsForValue().get(key);
        //2.3断言这个值不是空的，是空的就失效
        AssertUtil.isNotNull(o,"验证码失效");
        //2.4将这个值强转为RedisRegisterDto
        RedisRegisterDto redisRegisterDto = (RedisRegisterDto) o;
        //2.5断言前端传回来的值和redis存储的值一致
        AssertUtil.isEquals(registerDto.getSmsCode(),redisRegisterDto.getCode(),"两次密码不一致");

//        3.手机号不能被注册
        //3.1构造selectUserByMobile方法，根据mobile判断是否注册过
        User user = selectUserByPhone(registerDto.getMobile());
        //3.2断言user不存在，否则就报用户存在异常
        AssertUtil.isNull(user,"用户已存在");
//                4.==保存
//        保存t_login
//   。在service-uaa编写controller接口，调用service保存t_login数据
//   。为service-uaa的controller编写Feign，给service-user调用
//        保存user相关
        //4.1.构造一个saveLogin方法将前端传过来的值保存，返回JSONResult对象
        JSONResult jsonResult = saveLogin(registerDto);
        //4.2.断言保存成功为ture，
        AssertUtil.isTrue(jsonResult.isSuccess(),jsonResult.getMessage());
        //4.3.login保存成功了，断言返回的data数据不为空，空就报信息保存失败
        AssertUtil.isNotNull(jsonResult.getData(),"保存信息失败");
        //4.4.将data数据强转为Long loginId类型
        Long longId = Long.valueOf(jsonResult.getData().toString());


//        调用对应的service保存数据即可 t_user  t_user_base_info  t_user_account
        //5.保存user，构造saveUser方法保存loginId和mobile返回user
        user = saveUser(longId,registerDto.getMobile());
        //断言user不是空，不然就报保存失败
        AssertUtil.isNotNull(user.getId(),"保存失败");
        //6.保存userBaseInfo，需要保存id和渠道
        saveUserBaseInfo(user.getId(),registerDto.getRegChannel());
        //7.保存userAccount，构造方法保存id
        saveUserAccount(user.getId());
        //int i = 1/0;


    }

    /**
     * 拉黑
     * @param id
     */
    @Override
    @GlobalTransactional
    public void goBlack(Long id) {
        User user = new User();
        String phone = user.getPhone();
        userMapper.goBlack(id);

        saveRemoveBlack(id,phone);

    }

    private void saveRemoveBlack(Long id,String phone) {
        RemoveBlack removeBlack = new RemoveBlack();
        removeBlack.setId(id);
        removeBlack.setPhone(phone);
        removeBlack.setCreateTime(new Date());
        removeBlackService.insert(removeBlack);
    }

    /**
     * 注册时保存相关表实现方法
     * @param userId
     */
    private void saveUserAccount(Long userId) {
        UserAccount userAccount = new UserAccount();
        userAccount.setId(userId);
        userAccount.setCreateTime(new Date().getTime());
        userAccountService.insert(userAccount);
    }

    private void saveUserBaseInfo(Long userId, Integer regChannel) {
        UserBaseInfo userBaseInfo = new UserBaseInfo();
        userBaseInfo.setId(userId);
        userBaseInfo.setRegChannel(regChannel);
        userBaseInfo.setCreateTime(new Date().getTime());
        userBaseInfoService.insert(userBaseInfo);
    }


    private User saveUser(Long longId, String mobile) {
        User user = new User();
        user.setPhone(mobile);
        user.setLoginId(longId);
        user.setCreateTime(new Date().getTime());
        long state = BitStatesUtils.addState(BitStatesUtils.OP_REGISTED, BitStatesUtils.OP_ACTIVED);
        state = BitStatesUtils.addState(state, BitStatesUtils.OP_AUTHED_PHONE);
        user.setBitState(state);
        insert(user);
        return user;
    }

    private JSONResult saveLogin(RegisterDto registerDto) {
        Login login = new Login();
        login.setUsername(registerDto.getMobile());
        login.setPassword(registerDto.getPassword());
        login.setType(1);
        return loginFeignClient.saveOrUpdate(login);

    }

    private User selectUserByPhone(String mobile) {
        Wrapper<User> tWrapper = new EntityWrapper();
        tWrapper.eq("phone",mobile);  // where phone = 123123
        return selectOne(tWrapper);
    }
}
